#include <stdio.h>
#include <stdbool.h>

// 检查日期是否有效
bool isValidDate(int year, int month, int day)
{
  // 检查年份范围(12位最多表示4095)
  if (year < 0 || year > 4095)
    return false;

  // 检查月份范围
  if (month < 1 || month > 12)
    return false;

  // 检查日期范围
  if (day < 1)
    return false;

  // 检查每月的最大天数
  int maxDay;
  switch (month)
  {
  case 2:
    // 简单处理闰年(能被4整除)
    maxDay = (year % 4 == 0) ? 29 : 28;
    break;
  case 4:
  case 6:
  case 9:
  case 11:
    maxDay = 30;
    break;
  default:
    maxDay = 31;
  }

  return day <= maxDay;
}

// 使用位域的紧凑日期结构体
struct CompactDate
{
  unsigned int year : 12; // 12位表示年份(0-4095)
  // · 1-12月(实际只需4位) 使用5位可以同时满足 month(1-12) 和 day(1-31) 的存储需求
  // · 避免不同位数造成的混淆
  unsigned int month : 5;
  unsigned int day : 5; // 1-31日(需要5位) 每月最多有31天，需要5位(2^5=32)才能完整表示
};

// 普通结构体(用于对比内存占用)
struct NormalDate
{
  unsigned int year;
  unsigned int month;
  unsigned int day;
};

int main()
{
  struct CompactDate cDate;
  struct NormalDate nDate;
  int year, month, day;

  // 输入日期
  printf("请输入年份(0-4095): ");
  scanf("%d", &year);
  printf("请输入月份(1-12): ");
  scanf("%d", &month);
  printf("请输入日期(1-31): ");
  scanf("%d", &day);

  // 验证日期有效性
  if (!isValidDate(year, month, day))
  {
    printf("输入的日期无效!\n");
    return 1;
  }

  // 存储日期
  cDate.year = year;
  cDate.month = month;
  cDate.day = day;

  nDate.year = year;
  nDate.month = month;
  nDate.day = day;

  // 输出存储的日期
  printf("\n存储的日期为: %d年%d月%d日\n",
         cDate.year, cDate.month, cDate.day);

  // 显示内存占用情况
  printf("位域结构体CompactDate占用内存: %zu字节\n", sizeof(cDate));
  // %zu 是用于打印 size_t 类型的格式说明符，size_t 是一种无符号整数类型，通常用于表示对象的大小或数组的索引。
  printf("普通结构体NormalDate占用内存: %zu字节\n", sizeof(nDate));
  printf("内存节省比例: %.2f%%\n",
         (1.0 - (double)sizeof(cDate) / sizeof(nDate)) * 100);

  return 0;
}
